package org.realogic.cfm.plugin;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.realogic.cfm.KAppContext;
import org.realogic.cfm.KSystemEnvs;
import org.realogic.cfm.util.PropertiesLoader;

/**
 * 
 * 插件装载器
 * <p>
 * 负责系统的插件装载
 * 
 */
public final class PluginLoader {

	private static Logger LOGGER = Logger.getLogger(PluginLoader.class);

	private static PluginLoader instance = null;

	private final List<String> pluginIds = new ArrayList<String>(100);
	private final List<PluginDefinition> pluginDefinitions = new ArrayList<PluginDefinition>(100);

	private PluginLoader() {

	}

	public static final PluginLoader getInstance() {
		if (instance == null) {
			instance = new PluginLoader();
		}
		return instance;
	}

	public final void init() {
		long startTime = System.currentTimeMillis();
		File pluginHome = new File(KAppContext.getCfgHome(), "/plugin");
		if ((!pluginHome.exists()) || (!pluginHome.isDirectory())) {
			LOGGER.warn("系统插件定义文件路径不存在：" + pluginHome.getAbsolutePath());
			return;
		}

		// String userProps = System.getProperty("SEEYON_HOME");
		// if (userProps == null) {
		// userProps = AppContext.getCfgHome() + "/../../../../../";
		// LOGGER.warn("未配置SEEYON_HOME环境变量，使用默认路径：" + userProps);
		// }
		// Properties pluginCustomProps = null;
		// if (new File(userProps, "/base/conf/plugin.properties").exists()) {
		// pluginCustomProps = PropertiesLoader.load(new File(userProps,
		// "/base/conf/plugin.properties"));
		// } else {
		// LOGGER.warn(new File(userProps,
		// "/base/conf/plugin.properties").getAbsolutePath() +
		// " 文件不存在，使用插件默认配置！");
		// }

		File[] pluginFileArray = pluginHome.listFiles(new FileFilter() {
			public boolean accept(File f) {
				return f.isDirectory();
			}
		});
		for (File pluginFile : pluginFileArray) {
			File pluginCfg = new File(pluginFile, "pluginCfg.xml");
			if ((!pluginCfg.exists()) || (!pluginCfg.isFile())) {
				continue;
			}
			Properties props = PropertiesLoader.load(pluginCfg);
			String id = props.getProperty("id");
			String name = props.getProperty("name");
			String className = props.getProperty("className");
			if ((id == null) || ("".equals(id.trim()))) {
				LOGGER.error("插件不能加载, 'id' 未设置: " + pluginCfg.getAbsolutePath());
				continue;
			} else if (!pluginFile.getAbsolutePath().endsWith(id)) {
				LOGGER.error("插件不能加载, 插件的目录名称必须是 '" + id + "': " + pluginCfg.getAbsolutePath());
				continue;
			} else if ((name == null) || ("".equals(name.trim()))) {
				LOGGER.error("插件不能加载, 'name' 未设置: " + pluginCfg.getAbsolutePath());
				continue;
			}

			if (pluginIds.contains(id)) {
				LOGGER.warn("插件[" + id + "]的ID已经被使用,插件将不被启动.");
				continue;
			}

			PluginDefinition tmpPlugin = new PluginDefinition();
			tmpPlugin.setId(id);
			tmpPlugin.setName(name);
			tmpPlugin.setPluginFoler(pluginFile);
			
			Properties pluginProps = null;
			File pluginPropFile = new File(pluginFile, "pluginProperties.xml");
			if ((!pluginPropFile.exists()) || (!pluginPropFile.isFile())) {
				pluginPropFile = new File(pluginFile, "pluginProperties.properties");
			}
			if ((pluginPropFile.exists()) && (pluginPropFile.isFile())) {
				pluginProps = PropertiesLoader.load(pluginPropFile);
				if ((pluginProps != null) && (!pluginProps.isEmpty())) {
					tmpPlugin.setPluginProperties(pluginProps);
				}
			}
			if ((pluginProps != null) && (!pluginProps.isEmpty())) {
				List<String> removeList = new ArrayList<String>();
				@SuppressWarnings("rawtypes")
				Enumeration enus = pluginProps.keys();
				while (enus.hasMoreElements()) {
					String key = (String) enus.nextElement();
					if (!key.startsWith(id)) {
						removeList.add(key);
						LOGGER.error("Illegal plugin properties key '" + key + "' for '" + id + "', discarded.");
					}
				}
				for (String k : removeList) {
					pluginProps.remove(k);
				}
				KSystemEnvs.getInstance().putAll(pluginProps);
				LOGGER.debug("载入插件相关的配置属性: " + id);
			}
			
			
			if ((className != null) && (!"".equals(className))) {
				try {
					Plugin pi = (Plugin) Class.forName(className).newInstance();
					tmpPlugin.setPluginInstance(pi);
					if (!pi.isAllowStartup(tmpPlugin)) {
						LOGGER.warn("插件[" + tmpPlugin + "]的initializer[" + className + "]禁止了此插件的启动.");
						continue;
					}
				} catch (Exception e) {
					LOGGER.error("插件[" + tmpPlugin + "]的initializer[" + className + "]初始化失败.", e);
					continue;
				}
			}
			this.pluginDefinitions.add(tmpPlugin);
			LOGGER.info("发现插件 : " + tmpPlugin+",并启用该插件...");
		}
		LOGGER.info("扫描插件定义文件完毕. 耗时：" + (System.currentTimeMillis() - startTime) + " MS");
	}

	public List<String> getPluginIds() {
		return this.pluginIds;
	}

	public List<PluginDefinition> getPluginDefinitions() {
		return this.pluginDefinitions;
	}
}
